Skip to content

fix(ci): remove duplicate pull_request trigger from release workflow#392

Merged
perasperaactual merged 1 commit into
devfrom
fix/release-workflow-dual-trigger
Apr 29, 2026
Merged

fix(ci): remove duplicate pull_request trigger from release workflow#392
perasperaactual merged 1 commit into
devfrom
fix/release-workflow-dual-trigger

Conversation

@perasperaactual
Copy link
Copy Markdown
Contributor

Problem

The Release workflow had a dual-trigger race condition that caused a guaranteed push rejection on every PR merge to main.

Root cause

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
    types: [closed]

When a PR merges into main, GitHub fires both a push event and a pull_request: closed event at the same time. This spawned two concurrent Release workflow runs that both:

  1. Checked out main
  2. Versioned packages and committed locally
  3. Raced to git push origin main

The loser (whichever runner got there second) was always rejected with:

! [rejected] main -> main (fetch first)
error: failed to push some refs to 'https://github.com/Per-Aspera-LLC/stackwright'

This was observed in run 25080842050 triggered by PR #391. The push trigger alone is sufficient — merging a PR always creates a push event on the target branch.

Changes

Bug 1 (Critical): Remove the pull_request trigger block

The push: branches: [main] trigger alone covers all cases. Removed the entire pull_request block.

Bug 2 (Secondary): Harden the [skip ci] guard

github.event.head_commit.message is only populated for push events — it's null for pull_request events, which means the guard was silently a no-op for PR-triggered runs. Added an explicit github.event_name == 'push' check to make the intent clear and future-proof against any trigger re-addition.

Bug 3 (Minor): Remove provenance: true from actions/setup-node@v5

provenance is an npm publish flag, not a valid input for actions/setup-node. It caused a yellow warning annotation on every run. Provenance attestation is already correctly applied via --provenance in the npm publish command later in the workflow.

Diff

 on:
   push:
     branches:
       - main
-  pull_request:
-    branches:
-      - main
-    types:
-      - closed

-    if: "${{ !startsWith(github.event.head_commit.message, '...') }}"
+    if: "${{ github.event_name == 'push' && !startsWith(github.event.head_commit.message, '...') }}"

-          provenance: true

- Remove pull_request trigger: merging a PR to main always fires a push
  event, so the pull_request: closed trigger was redundant and caused two
  concurrent release runs to race — the loser always got rejected with a
  'fetch first' push error (observed in run 25080842050 / PR #391).

- Tighten the [skip ci] guard: github.event.head_commit.message is only
  populated on push events (it is null on pull_request events), so add an
  explicit github.event_name == 'push' check to make the intent clear and
  future-proof against any accidental trigger re-addition.

- Remove provenance: true from actions/setup-node@v5: provenance is an
  npm publish flag, not a valid setup-node input. It caused a yellow
  warning annotation on every run. Provenance attestation is already
  correctly applied via --provenance in the npm publish command.
@perasperaactual perasperaactual merged commit 504c699 into dev Apr 29, 2026
3 checks passed
@perasperaactual perasperaactual deleted the fix/release-workflow-dual-trigger branch April 29, 2026 12:50
perasperaactual added a commit that referenced this pull request Apr 29, 2026
* fix(deploy): enable static export for R2 bucket hosting (#332)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(deploy): add trailing slash support for R2 static hosting (#334)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(deploy): migrate from R2 to Cloudflare Pages (#336)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* Fix/cloudflare pages (#337)

* fix(deploy): migrate from R2 to Cloudflare Pages

* fix(deploy): use env vars for deployment variables

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* feat(hooks): add @stackwright/hooks-registry for cross-module singleton (#341)

* feat(hooks): add @stackwright/hooks-registry for cross-module singleton

- Create new @stackwright/hooks-registry package using Symbol.for() pattern
- Update @stackwright/scaffold-core to re-export from shared registry
- Fix fallback:'blocking' + output:'export' incompatibility in template
- Update E2E config to serve static out/ directory

Fixes module isolation where Pro packages' hooks weren't visible to CLI.

* fix(hooks): add resetForTesting export and improve singleton tests

* fix: address lint warnings for PR #341

* chore: update visual regression baselines and SBOM files

* fix(deps): pin undici to ^7.0.0 for jsdom compatibility

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* docs: document shared validation module architecture (fixes #338) (#342)

* feat(hooks): add @stackwright/hooks-registry for cross-module singleton

- Create new @stackwright/hooks-registry package using Symbol.for() pattern
- Update @stackwright/scaffold-core to re-export from shared registry
- Fix fallback:'blocking' + output:'export' incompatibility in template
- Update E2E config to serve static out/ directory

Fixes module isolation where Pro packages' hooks weren't visible to CLI.

* fix(hooks): add resetForTesting export and improve singleton tests

* fix: address lint warnings for PR #341

* chore: update visual regression baselines and SBOM files

* fix(deps): pin undici to ^7.0.0 for jsdom compatibility

* docs: add ADR 006 for shared validation module (fixes #338)

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(core): resolve theme tokens in icon color prop (fixes #339) (#343)

* fix(core): resolve theme tokens in icon color prop (fixes #339)

* chore: add changeset for #339 fix

* fix(core): map background token to --sw-color-bg (fixes #343 review)

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* feat(security): add secrets scanning and plugin security guidelines (#345)

* feat(security): add secrets scanning and plugin security guidelines (fixes #244, #246)

* fix(security): use gitleaks v1 (MIT) and fix workflow configuration

* refactor(security): use gitleaks CLI instead of GitHub Action

- Replace gitleaks-action with direct CLI invocation
- CLI is MIT licensed, no license key required
- Exit code 1 = leaks found (fails CI), 0 = clean (passes)
- Add Go setup step to install gitleaks v9

* fix(security): use --filter for pnpm audit to avoid workspace conflicts

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* feat(types,build-scripts): add env var resolution for integration secrets (#245)

* chore: add changeset for #245

* feat(types,build-scripts): env var resolution for integration secrets (#245) (#347)

* feat(types,build-scripts): add env var resolution for integration secrets (#245)

* chore: add changeset for #245

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(security): add plugin config schema validation (#242) (#349)

* fix(security): add configSchema field to PrebuildPlugin interface

This commit addresses security issue #242 by adding schema validation for
integration configs in the Stackwright prebuild pipeline.

Changes:
- Add configSchema field to PrebuildPlugin interface in packages/types
- Add validateIntegrationConfig() and validateIntegrations() functions
  to packages/build-scripts/src/prebuild.ts
- Integrate validation into the prebuild pipeline after env var resolution
- Add comprehensive tests for plugin config schema validation

Security benefits:
- Prevents prototype pollution attacks (__proto__, constructor)
- Validates plugin-specific configuration options
- Enforces type safety for integration configs

The validation is opt-in for plugins - they declare a configSchema if they
want their integration configs validated. Existing plugins without a
configSchema continue to work as before (with a warning in development).

fixes #242

* fix: add plugin config schema validation (#242)

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* feat(nextjs): add security headers - CSP, HSTS, COOP/CORP/COEP (#243) (#350)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(cli): remove duplicate preInstall hook call from processTemplate (#362)

* fix(cli): remove duplicate preInstall hook call from processTemplate (fixes #351)

* chore: add changeset for #351 fix

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* docs: remove ROADMAP.md and clean up stale documentation references (#363)

- Delete ROADMAP.md (roadmap lives in GitHub Issues; use `pnpm stackwright -- board`)
- Update 3 stale ROADMAP.md references in CONTRIBUTING.md
- Fix duplicate/truncated paragraph at end of PHILOSOPHY.md
- Update PHILOSOPHY.md intro to point to GitHub Issues instead of ROADMAP.md
- Delete docs/archive/ (6 completed-work summaries; preserved in git history)
- Delete orphaned docs/sbom-ci-workflow.md (no inbound refs, CI already covers it)
- Rename docs/security-model-for-docs.md → docs/SECURITY-MODEL.md
- Update inbound links to SECURITY-MODEL.md in docs/PLUGIN_SECURITY.md

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* chore: consolidate dependabot dependency updates (#364)

* static export fixes (#335)

* fix(deploy): enable static export for R2 bucket hosting (#332)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(deploy): add trailing slash support for R2 static hosting (#334)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* release CI security fixes (#348)

* fix(deploy): enable static export for R2 bucket hosting (#332)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(deploy): add trailing slash support for R2 static hosting (#334)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(deploy): migrate from R2 to Cloudflare Pages (#336)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* Fix/cloudflare pages (#337)

* fix(deploy): migrate from R2 to Cloudflare Pages

* fix(deploy): use env vars for deployment variables

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* feat(hooks): add @stackwright/hooks-registry for cross-module singleton (#341)

* feat(hooks): add @stackwright/hooks-registry for cross-module singleton

- Create new @stackwright/hooks-registry package using Symbol.for() pattern
- Update @stackwright/scaffold-core to re-export from shared registry
- Fix fallback:'blocking' + output:'export' incompatibility in template
- Update E2E config to serve static out/ directory

Fixes module isolation where Pro packages' hooks weren't visible to CLI.

* fix(hooks): add resetForTesting export and improve singleton tests

* fix: address lint warnings for PR #341

* chore: update visual regression baselines and SBOM files

* fix(deps): pin undici to ^7.0.0 for jsdom compatibility

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* docs: document shared validation module architecture (fixes #338) (#342)

* feat(hooks): add @stackwright/hooks-registry for cross-module singleton

- Create new @stackwright/hooks-registry package using Symbol.for() pattern
- Update @stackwright/scaffold-core to re-export from shared registry
- Fix fallback:'blocking' + output:'export' incompatibility in template
- Update E2E config to serve static out/ directory

Fixes module isolation where Pro packages' hooks weren't visible to CLI.

* fix(hooks): add resetForTesting export and improve singleton tests

* fix: address lint warnings for PR #341

* chore: update visual regression baselines and SBOM files

* fix(deps): pin undici to ^7.0.0 for jsdom compatibility

* docs: add ADR 006 for shared validation module (fixes #338)

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(core): resolve theme tokens in icon color prop (fixes #339) (#343)

* fix(core): resolve theme tokens in icon color prop (fixes #339)

* chore: add changeset for #339 fix

* fix(core): map background token to --sw-color-bg (fixes #343 review)

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* feat(security): add secrets scanning and plugin security guidelines (#345)

* feat(security): add secrets scanning and plugin security guidelines (fixes #244, #246)

* fix(security): use gitleaks v1 (MIT) and fix workflow configuration

* refactor(security): use gitleaks CLI instead of GitHub Action

- Replace gitleaks-action with direct CLI invocation
- CLI is MIT licensed, no license key required
- Exit code 1 = leaks found (fails CI), 0 = clean (passes)
- Add Go setup step to install gitleaks v9

* fix(security): use --filter for pnpm audit to avoid workspace conflicts

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* feat(types,build-scripts): add env var resolution for integration secrets (#245)

* chore: add changeset for #245

* feat(types,build-scripts): env var resolution for integration secrets (#245) (#347)

* feat(types,build-scripts): add env var resolution for integration secrets (#245)

* chore: add changeset for #245

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* chore: consolidate dependabot dependency updates

* chore: apply review fixes to dependabot batch update

* chore: add changeset for dependabot dependency consolidation

* fix(ci): delete lockfile before pnpm install on PRs to ensure fresh generation

* fix(ci): add lockfile diagnostics to debug broken lockfile issue

* fix(ci): clear stale pnpm store on PR runs to prevent broken lockfile generation

* ci: add detailed lockfile diagnostics after pnpm install

* ci: add comprehensive lockfile content analysis after pnpm install

* fix(ci): revert pnpm/action-setup to @v4 to fix ERR_PNPM_BROKEN_LOCKFILE on audit

pnpm/action-setup@v6 sets up the pnpm environment in a way that causes
pnpm audit to fail with ERR_PNPM_BROKEN_LOCKFILE even on valid lockfiles.
The dev branch uses @v4 which works correctly with pnpm@10.30.3.
Reverting to @v4 restores parity with dev and unblocks CI.

* ci: remove duplicate audit from lint-and-format, bump pnpm to 10.33.0

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(deps): bump hono override to >=4.12.14 to patch GHSA-458j-xx4x-4375

* fix(cli): --install flag now runs pnpm install before postInstall hooks (fixes #352) (#365)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(core): prevent duplicate TopAppBar rendering — double dark-mode toggle icon (#366)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* chore: adding image files to example pages

* fix: remove broken changeset referencing non-existent stackwright package

* fix: remove broken changeset referencing non-existent stackwright package

* feat(cli): add --content flag to page add for inline YAML (#188) (#367)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* chore(deps-dev): bump @changesets/cli from 2.30.0 to 2.31.0

Bumps [@changesets/cli](https://github.com/changesets/changesets) from 2.30.0 to 2.31.0.
- [Release notes](https://github.com/changesets/changesets/releases)
- [Commits](https://github.com/changesets/changesets/compare/@changesets/cli@2.30.0...@changesets/cli@2.31.0)

---
updated-dependencies:
- dependency-name: "@changesets/cli"
  dependency-version: 2.31.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* feat(types,build-scripts): pro plugin content schema extension + YAML mapping-key normalization (#381)

* feat(cli): add --content flag to page add for inline YAML (#188)

* feat(types,build-scripts): add plugin content schema extension and YAML normalization

- Add `contentItemSchemas` and `knownContentTypeKeys` to PrebuildPlugin interface
- Add `buildExtendedPageContentSchema()` to @stackwright/types for merging OSS and plugin schemas
- Add `ValidatePageContentOptions` to validatePageContent() for plugin-aware validation
- Add content format normalization in runPrebuild: YAML mapping-key-as-type format
  ({ page_header: { title } }) is auto-normalized to OSS type-field format
  ({ type: 'page_header', title }) before validation and processing
- Plugin contentItemSchemas and knownContentTypeKeys are now collected and applied
  during page validation, enabling pro content types to pass schema validation

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix: basic-ftp HIGH vuln pnpm override, perf workflow playwright + branch fix

* fix(build-scripts): preserve this binding in executePluginHook (#383)

* fix(build-scripts): preserve this binding in executePluginHook

Plugin lifecycle hooks (beforeBuild, afterBuild) are extracted as method
references and then called without a receiver, stripping `this` in strict
mode ES classes. Any plugin that calls a private method from a lifecycle
hook throws "Cannot read properties of undefined".

Fix: use hookFn.call(plugin, context) so the plugin instance is always
the receiver, regardless of how the hook is implemented.

Reproducer: @stackwright-pro/openapi OpenAPIPlugin.beforeBuild calls
this.processIntegration() — was crashing pnpm build in marine-logistics.

* test(build-scripts): add regression tests for plugin hook this binding

Covers the class-method this-binding fix in executePluginHook:
- Class-based plugins that call private methods from beforeBuild/afterBuild
- Context shape passed to hooks (siteConfig + projectRoot)
- Error wrapping behavior (plugin name + hook included in thrown message)

No plugin hook tests existed before this PR; bugs drive CI.

* chore: add changeset for build-scripts plugin this-binding fix

---------

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix: remove hardcoded pnpm version from CI workflows

* chore(*): uuid update to version 14 (#385)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* chore: enter prerelease mode [skip ci]

* chore: bump prerelease versions [skip ci]

* chore(*): uuid update to version 14 (#387)

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(build-scripts): create parent dir for nested page slug output files (#389)

When a page lives under a nested directory (e.g. pages/missions/[id]/content.yml),
the prebuild derives a slug of 'missions/[id]' and tries to write
public/stackwright-content/missions/[id].json. The parent directory
'public/stackwright-content/missions/' was never created, causing ENOENT.

Added fs.mkdirSync(path.dirname(outPath), { recursive: true }) before
the writeFileSync call. No-op for root-level slugs where the parent
is already contentOutDir itself.

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* chore: bump prerelease versions [skip ci]

* fix(ci): remove duplicate pull_request trigger from release workflow (#392)

- Remove pull_request trigger: merging a PR to main always fires a push
  event, so the pull_request: closed trigger was redundant and caused two
  concurrent release runs to race — the loser always got rejected with a
  'fetch first' push error (observed in run 25080842050 / PR #391).

- Tighten the [skip ci] guard: github.event.head_commit.message is only
  populated on push events (it is null on pull_request events), so add an
  explicit github.event_name == 'push' check to make the intent clear and
  future-proof against any accidental trigger re-addition.

- Remove provenance: true from actions/setup-node@v5: provenance is an
  npm publish flag, not a valid setup-node input. It caused a yellow
  warning annotation on every run. Provenance attestation is already
  correctly applied via --provenance in the npm publish command.

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* fix(changeset): correct phantom version baselines in pre.json, remove consumed changeset (#396)

After PR #391 merged to main, the automated release workflow bumped
build-scripts→0.5.1, cli→0.8.1, mcp→0.4.1, and launch-stackwright→0.2.1,
but all npm publishes 404'd (packages not yet on the public registry). The
back-merge of main into dev wrote those phantom stable versions into the
dev package.json files, corrupting the prerelease state in two ways:

1. pre.json initialVersions was stale (still listed the pre-bump versions
   0.5.0, 0.8.0, 0.4.0, 0.2.0), causing changeset status to error with
   'Some packages have been changed but no changesets were found.'

2. pre.json changesets array listed all 10 IDs as 'already applied'.
   assembleReleasePlan filters out any changeset whose ID is in this array,
   so getReleasePlan returned 0 changesets and 0 releases. Combined with
   getVersionableChangedPackages finding real changes vs main, the
   changedPackages > 0 && changesets === 0 error condition fired.

Fix: update the 4 phantom initialVersions to match current package.json,
clear pre.json changesets to [] so all 10 pending .md files are treated as
unapplied, and delete the zombie fix-prebuild-mkdir-nested-slugs changeset
(already in the 0.5.1 CHANGELOG; this avoids a duplicate entry in the next
release's CHANGELOG).

Result: pnpm changeset status exits 0 and correctly reports 3 minor and 8
patch bumps across the 10 pending changesets.

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* chore: bump prerelease versions [skip ci]

* fix(core): bundle prismjs to eliminate bare ESM sub-path import errors (#397)

Add noExternal: ['prismjs'] to tsup.config.ts so esbuild inlines prismjs at
build time. Previously tsup auto-externalized prismjs (it's in dependencies),
which left bare imports like 'prismjs/components/prism-javascript' verbatim
in the published .mjs. Node.js ESM strict resolver cannot find these paths
without a .js extension on legacy CJS packages with no exports map, throwing
ERR_MODULE_NOT_FOUND.

Also adds 17 regression tests for prismHighlighter covering: plain-text
fallback, language alias resolution, token shape contract, getTokenColor
light/dark palettes, and highlightCodeWithMode end-to-end.

Co-authored-by: Stackwright Bot <bot@per-aspera.dev>

* chore: bump prerelease versions [skip ci]

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Stackwright Bot <bot@per-aspera.dev>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant